#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "protocol.hpp"

using namespace std;

class tcp_client
{
public:
    tcp_client(string ip, uint16_t port)
        : _ip(ip), _port(port), _sockfd(-1) {}

    void client_init()
    {
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0)
        {
            cout << "create socket error" << endl;
            exit(0);
        }
        else
            cout << "create socket success" << endl;

        struct sockaddr_in to_server;
        to_server.sin_family = AF_INET;
        to_server.sin_port = htons(_port);
        to_server.sin_addr.s_addr = inet_addr(_ip.c_str());
        socklen_t len = sizeof to_server;
        
        int check = connect(_sockfd, (struct sockaddr *)&to_server, len);
        if (check == -1)
        {
            cout << "connect server error" << endl;
            exit(0);
        }
        else
            cout << "connect server success" << endl;
    }

    void client_start()
    {
        while (true)
        {
            string commend; 
            request req;
            cout << "请输入要计算的操作: " << endl;
            getline(std::cin, commend);
            cout << commend <<endl;

            auto left_pos = commend.find(SEP);
            auto right_pos = commend.rfind(SEP);

            if (left_pos == string::npos || right_pos == string::npos)
            {
                cout << "enter error commend" <<endl;
                break;
            }

            if (left_pos == right_pos)
            {
                cout << "enter error commend" <<endl;
                break;
            }

            req._x = stoi(commend.substr(0, left_pos));
            req._op = commend[left_pos + 1];
            req._y = stoi(commend.substr(right_pos+1));

            string send_to_server;
            req.serializa(&send_to_server);
            send_to_server = enLength(send_to_server);
            send(_sockfd, send_to_server.c_str(), send_to_server.size(), 0);

            char recv_buff[4096] = {0};
            string inbuff;
            response resp;
            ssize_t size = recv(_sockfd, recv_buff, sizeof recv_buff-1, 0);
            if (size > 0)
            {
                recv_buff[size] = 0;
                inbuff += recv_buff;
                auto pos = inbuff.find(LINE_SEP);
                string content_num = inbuff.substr(0, pos);
                int text_size = stoi(content_num);
                string all_text = inbuff.substr(0, content_num.size()+2*LINE_SEP_LEN + text_size);
                string content;
                deLength(all_text, &content);
                
                resp.deserializa(content);
                switch(resp._exitcode)
                {
                    case OK:
                        cout << "计算结果为："<< resp._result <<endl;
                        break;
                    case DIV_ZERO:
                        cout << "你的除数为0，这是不允许的"<<endl;
                        break;
                    case MOD_ZERO:
                        cout << "你的模数为0，这是不允许的"<<endl;
                        break;
                    case OP_ERROR:
                        cout << "你的输入操作是非法的，请确认后重新输入"<<endl;
                        break;
                }
            }
        }
    }

private:
    string _ip;
    uint16_t _port;
    int _sockfd;
};